import CryptoJS from "crypto-js/crypto-js"; //引用AES源码js
import { useState, useEffect, useRef, useCallback} from 'react';

export const checkRules = (type) => {
  switch(type) {
    case 'telPhone' :
      return { 
        required: true, 
        pattern: /^1[34578]\d{9}$/,
        message: '手机号格式不正确'
      }
    case 'idCard' :
      return { 
        required: true, 
        pattern: /^(^[1-9]\d{7}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}$)|(^[1-9]\d{5}[1-9]\d{3}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])((\d{4})|\d{3}[Xx])$)$/,
        message: '身份证格式不正确',
      }
    case 'null' :
      return {
        required: true,
        message: '你的输入为空',
      }
    case 'number' :
      return {
        required: true,
        pattern: /^\+?[1-9][0-9]*$/,
        message: '请输入正确的数字'
      }
    case 'name' :
      return {
        required: true,
        pattern: /^[\u2E80-\u9FFF]+$/,
        message: '请输入汉字姓名'
      }
    case 'password':
      return {
        pattern: /^(?=.*\d)(?=.*[A-Za-z])[\x20-\x7e]{6,15}$/,
        message: '你所输入的密码不符合标准，请重新输入6~15位字母+数字密码',
      }
    default :
      return;
  }
}
export const useSyncCallback = callback => {
  const [proxyState, setProxyState] = useState({ current: false })

  const Func = useCallback(() => {
      setProxyState({ current: true })
  // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [proxyState])

  useEffect(() => {
      if (proxyState.current === true) setProxyState({ current: false })
  }, [proxyState])

  useEffect(() => {
    proxyState.current && callback()
  })

  return Func
}
export const useDebounceFn = (func, wait, immediate) => {
  const timeout = useRef();
  /* 函数组件的this其实没啥多大的意义，这里我们就把this指向func好了 */
  const fnRef = useRef(func);

  /*  useDebounceFn 重新触发 func 可能会改变，这里做下更新 */
  useEffect(() => {
      fnRef.current = func;
  }, [ func ]);

  /* 
      timeout.current做了缓存，永远是最新的值
      cancel 虽然看着没有依赖项了
      其实它的隐形依赖项是timeout.current
  */
  const cancel = useCallback(function() {
      timeout.current && clearTimeout(timeout.current);
  }, []);

  /* 相关函数 func 可能会返回值，这里也要缓存 */
  const resultRef = useRef();
  function resDebounced(...args) {
      //args就是事件对象event

      // 一直触发一直清除上一个打开的延时器
      cancel();

      if (immediate) {
          // 第一次触发，timeout===undefined恰好可以利用timeout的值
          const callNow = !timeout.current;
          timeout.current = setTimeout(function() {
              timeout.current = null;
          }, wait);
          /* this指向func好了 */
          if (callNow) resultRef.current = fnRef.current.apply(fnRef.current, args);

      } else {
          // 停止触发，只有最后一个延时器被保留
          timeout.current = setTimeout(function() {
              timeout.current = null;
              // func绑定this和事件对象event，还差一个函数返回值
              resultRef.current = fnRef.current.apply(fnRef.current, args);
          }, wait);
      };
      return resultRef.current;
  };
  resDebounced.cancal = function(){
      cancel();
      timeout.current = null;
  };
  
  /* resDebounced 被 useCallback 缓存 */
  /* 
      这里也有个难点，数组依赖项如何天蝎，因为它决定了函数何时更新
      1. useDebounceFn 重新触发 wait 可能会改变，应该有 wait
      2. useDebounceFn 重新触发 immediate 可能会改变，应该有 immediate
      3. 当防抖时，resDebounced 不应该读取缓存，而应该实时更新执行
      这时候估计你想不到用哪个变量来做依赖！被难住了吧，哈哈哈哈哈😂😂😂
      这时候你应该想实时更新，resDebounced函数里面哪个模块一直是实时更新的。
      没错就是清除延时器，这条语句。很明显依赖项就应该是它。应该怎么写呢？？？
      提出来，看我给你秀一把。
  */
  return useCallback(resDebounced, [ wait, cancel, immediate ]);
}
export const deepclone = (obj) => {
  return JSON.parse(JSON.stringify(obj));
}

// byte数组转码Uint8Array
export const wordArrayToUint8 = (array, length = array.length * 4)=> {
  var bin = new Uint8Array(Math.min(array.length * 4, length));
  for (var i = 0; i < array.length; i++) {
    var num = array[i];
    if (num < 0) {
      num = array[i] + 0x100000000;
    }
    bin[i * 4 + 0] = (num >>> 24) & 0xff;
    bin[i * 4 + 1] = (num >>> 16) & 0xff;
    bin[i * 4 + 2] = (num >>> 8) & 0xff;
    bin[i * 4 + 3] = (num >>> 0) & 0xff;
  }
  return bin;
}
// 数组去重
export const unqie = (arr, key = "key")=> {
  let map = new Map()
  for (let i of arr) {
    if (!map.has(i[key])) {
      map.set(i[key], i)
    }
  }
  return [...map.values()]
}
// 加密
export const encrypt = (content, key) => {
  var sKey = CryptoJS.enc.Utf8.parse(key);
  var sContent = CryptoJS.enc.Utf8.parse(content);
  var encrypted = CryptoJS.AES.encrypt(sContent, sKey, {
    mode: CryptoJS.mode.ECB,
    padding: CryptoJS.pad.Pkcs7,
  });
  return encrypted.toString();
}
  // 解密
export const decrypt = (content, key) => {
  var sKey = CryptoJS.enc.Utf8.parse(key);
  var decrypt = CryptoJS.AES.decrypt(content, sKey, {
    mode: CryptoJS.mode.ECB,
    padding: CryptoJS.pad.Pkcs7,
  });
  let data;
  // 如果能直接解密成功即 用户发的数据 否则 为后端gzip压缩数据
  try {
    data = CryptoJS.enc.Utf8.stringify(decrypt).toString();
    return data;
  } catch (err) {
    var retArray = [];
    if (decrypt.sigBytes > 0) {
    retArray = wordArrayToUint8(decrypt.words, decrypt.sigBytes);
    }
    return retArray;
  }
}